home *** CD-ROM | disk | FTP | other *** search
/ Komputer for Alle 2004 #2 / K-CD-2-2004.ISO / OpenOffice Sv / f_0397 / python-core-2.2.2 / lib / SimpleXMLRPCServer.py < prev    next >
Encoding:
Python Source  |  2003-07-18  |  8.2 KB  |  251 lines

  1. """Simple XML-RPC Server.
  2.  
  3. This module can be used to create simple XML-RPC servers
  4. by creating a server and either installing functions, a
  5. class instance, or by extending the SimpleXMLRPCRequestHandler
  6. class.
  7.  
  8. A list of possible usage patterns follows:
  9.  
  10. 1. Install functions:
  11.  
  12. server = SimpleXMLRPCServer(("localhost", 8000))
  13. server.register_function(pow)
  14. server.register_function(lambda x,y: x+y, 'add')
  15. server.serve_forever()
  16.  
  17. 2. Install an instance:
  18.  
  19. class MyFuncs:
  20.     def __init__(self):
  21.         # make all of the string functions available through
  22.         # string.func_name
  23.         import string
  24.         self.string = string
  25.     def pow(self, x, y): return pow(x, y)
  26.     def add(self, x, y) : return x + y
  27. server = SimpleXMLRPCServer(("localhost", 8000))
  28. server.register_instance(MyFuncs())
  29. server.serve_forever()
  30.  
  31. 3. Install an instance with custom dispatch method:
  32.  
  33. class Math:
  34.     def _dispatch(self, method, params):
  35.         if method == 'pow':
  36.             return apply(pow, params)
  37.         elif method == 'add':
  38.             return params[0] + params[1]
  39.         else:
  40.             raise 'bad method'
  41. server = SimpleXMLRPCServer(("localhost", 8000))
  42. server.register_instance(Math())
  43. server.serve_forever()
  44.  
  45. 4. Subclass SimpleXMLRPCRequestHandler:
  46.  
  47. class MathHandler(SimpleXMLRPCRequestHandler):
  48.     def _dispatch(self, method, params):
  49.         try:
  50.             # We are forcing the 'export_' prefix on methods that are
  51.             # callable through XML-RPC to prevent potential security
  52.             # problems
  53.             func = getattr(self, 'export_' + method)
  54.         except AttributeError:
  55.             raise Exception('method "%s" is not supported' % method)
  56.         else:
  57.             return apply(func, params)
  58.  
  59.     def log_message(self, format, *args):
  60.         pass # maybe do something fancy like write the messages to a file
  61.  
  62.     def export_add(self, x, y):
  63.         return x + y
  64.  
  65. server = SimpleXMLRPCServer(("localhost", 8000), MathHandler)
  66. server.serve_forever()
  67. """
  68.  
  69. # Written by Brian Quinlan (brian@sweetapp.com).
  70. # Based on code written by Fredrik Lundh.
  71.  
  72. import xmlrpclib
  73. import SocketServer
  74. import BaseHTTPServer
  75. import sys
  76.  
  77. class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
  78.     """Simple XML-RPC request handler class.
  79.  
  80.     Handles all HTTP POST requests and attempts to decode them as
  81.     XML-RPC requests.
  82.  
  83.     XML-RPC requests are dispatched to the _dispatch method, which
  84.     may be overriden by subclasses. The default implementation attempts
  85.     to dispatch XML-RPC calls to the functions or instance installed
  86.     in the server.
  87.     """
  88.  
  89.     def do_POST(self):
  90.         """Handles the HTTP POST request.
  91.  
  92.         Attempts to interpret all HTTP POST requests as XML-RPC calls,
  93.         which are forwarded to the _dispatch method for handling.
  94.         """
  95.  
  96.         try:
  97.             # get arguments
  98.             data = self.rfile.read(int(self.headers["content-length"]))
  99.             params, method = xmlrpclib.loads(data)
  100.  
  101.             # generate response
  102.             try:
  103.                 response = self._dispatch(method, params)
  104.                 # wrap response in a singleton tuple
  105.                 response = (response,)
  106.             except:
  107.                 # report exception back to server
  108.                 response = xmlrpclib.dumps(
  109.                     xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value))
  110.                     )
  111.             else:
  112.                 response = xmlrpclib.dumps(response, methodresponse=1)
  113.         except:
  114.             # internal error, report as HTTP server error
  115.             self.send_response(500)
  116.             self.end_headers()
  117.         else:
  118.             # got a valid XML RPC response
  119.             self.send_response(200)
  120.             self.send_header("Content-type", "text/xml")
  121.             self.send_header("Content-length", str(len(response)))
  122.             self.end_headers()
  123.             self.wfile.write(response)
  124.  
  125.             # shut down the connection
  126.             self.wfile.flush()
  127.             self.connection.shutdown(1)
  128.  
  129.     def _dispatch(self, method, params):
  130.         """Dispatches the XML-RPC method.
  131.  
  132.         XML-RPC calls are forwarded to a registered function that
  133.         matches the called XML-RPC method name. If no such function
  134.         exists then the call is forwarded to the registered instance,
  135.         if available.
  136.  
  137.         If the registered instance has a _dispatch method then that
  138.         method will be called with the name of the XML-RPC method and
  139.         it's parameters as a tuple
  140.         e.g. instance._dispatch('add',(2,3))
  141.  
  142.         If the registered instance does not have a _dispatch method
  143.         then the instance will be searched to find a matching method
  144.         and, if found, will be called.
  145.  
  146.         Methods beginning with an '_' are considered private and will
  147.         not be called by SimpleXMLRPCServer.
  148.         """
  149.  
  150.         func = None
  151.         try:
  152.             # check to see if a matching function has been registered
  153.             func = self.server.funcs[method]
  154.         except KeyError:
  155.             if self.server.instance is not None:
  156.                 # check for a _dispatch method
  157.                 if hasattr(self.server.instance, '_dispatch'):
  158.                     return self.server.instance._dispatch(method, params)
  159.                 else:
  160.                     # call instance method directly
  161.                     try:
  162.                         func = _resolve_dotted_attribute(
  163.                             self.server.instance,
  164.                             method
  165.                             )
  166.                     except AttributeError:
  167.                         pass
  168.  
  169.         if func is not None:
  170.             return apply(func, params)
  171.         else:
  172.             raise Exception('method "%s" is not supported' % method)
  173.  
  174.     def log_request(self, code='-', size='-'):
  175.         """Selectively log an accepted request."""
  176.  
  177.         if self.server.logRequests:
  178.             BaseHTTPServer.BaseHTTPRequestHandler.log_request(self, code, size)
  179.  
  180.  
  181. def _resolve_dotted_attribute(obj, attr):
  182.     """Resolves a dotted attribute name to an object.  Raises
  183.     an AttributeError if any attribute in the chain starts with a '_'.
  184.     """
  185.     for i in attr.split('.'):
  186.         if i.startswith('_'):
  187.             raise AttributeError(
  188.                 'attempt to access private attribute "%s"' % i
  189.                 )
  190.         else:
  191.             obj = getattr(obj,i)
  192.     return obj
  193.  
  194.  
  195. class SimpleXMLRPCServer(SocketServer.TCPServer):
  196.     """Simple XML-RPC server.
  197.  
  198.     Simple XML-RPC server that allows functions and a single instance
  199.     to be installed to handle requests.
  200.     """
  201.  
  202.     def __init__(self, addr, requestHandler=SimpleXMLRPCRequestHandler,
  203.                  logRequests=1):
  204.         self.funcs = {}
  205.         self.logRequests = logRequests
  206.         self.instance = None
  207.         SocketServer.TCPServer.__init__(self, addr, requestHandler)
  208.  
  209.     def register_instance(self, instance):
  210.         """Registers an instance to respond to XML-RPC requests.
  211.  
  212.         Only one instance can be installed at a time.
  213.  
  214.         If the registered instance has a _dispatch method then that
  215.         method will be called with the name of the XML-RPC method and
  216.         it's parameters as a tuple
  217.         e.g. instance._dispatch('add',(2,3))
  218.  
  219.         If the registered instance does not have a _dispatch method
  220.         then the instance will be searched to find a matching method
  221.         and, if found, will be called.
  222.  
  223.         Methods beginning with an '_' are considered private and will
  224.         not be called by SimpleXMLRPCServer.
  225.  
  226.         If a registered function matches a XML-RPC request, then it
  227.         will be called instead of the registered instance.
  228.         """
  229.  
  230.         self.instance = instance
  231.  
  232.     def register_function(self, function, name = None):
  233.         """Registers a function to respond to XML-RPC requests.
  234.  
  235.         The optional name argument can be used to set a Unicode name
  236.         for the function.
  237.  
  238.         If an instance is also registered then it will only be called
  239.         if a matching function is not found.
  240.         """
  241.  
  242.         if name is None:
  243.             name = function.__name__
  244.         self.funcs[name] = function
  245.  
  246. if __name__ == '__main__':
  247.     server = SimpleXMLRPCServer(("localhost", 8000))
  248.     server.register_function(pow)
  249.     server.register_function(lambda x,y: x+y, 'add')
  250.     server.serve_forever()
  251.